Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

586
Views
Convertir doble[,] a IntPtr C#

Necesito convertir una matriz doble en c# en un IntPtr para enviarlo correctamente a mi c DLL. He podido convertir con éxito de IntPtr a double[,] usando el método de esta respuesta . También encontré otra respuesta que está cerca de lo que necesito pero trata con matrices 1D.

Me falta algo en mi lógica y obtengo el código de error después de un bloqueo: Managed ' ha salido con el código -1073740940 (0xc0000374).

Esto es lo que tengo hasta ahora

 IntPtr p = Marshal.AllocHGlobal(rows * columns); for (int i = 0; i < rows; i++) //rows { double[] temp = new double[columns]; for (int x = 0; x < columns; x++) temp[x] = input.cells[i, x]; Marshal.Copy(temp, 0, p, columns); p = (IntPtr)(p.ToInt64() + IntPtr.Size); } toReturn.cells = p; Marshal.FreeHGlobal(p); return toReturn;

toReturn.cells es mi IntPtr dentro de una estructura que devuelvo. las celdas están estructuradas como celdas [filas, columnas]

Los IntPtr todavía son muy nuevos para mí.

Editar: gracias a Harold. sus sugerencias funcionaron maravillosamente

over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

Hay varias cosas mal con eso.

Primero, rows * columns no es el tamaño de los datos, es solo el número total de elementos. Los elementos no son de un byte cada uno, sino de ocho, o sizeof(double) si lo prefiere.

En segundo lugar, p se actualiza mediante p = (IntPtr)(p.ToInt64() + IntPtr.Size); (es decir, avanzándolo en 4 u 8 bytes dependiendo de qué tan grandes sean los punteros en el modo actual), pero ha escrito columns * 8 (o columns * sizeof(double) ) bytes de datos. Avanzar p en menos de columns * 8 hace que las escrituras se sobrescriban entre sí, por lo que no todos los datos terminan en el resultado. Por cierto, las conversiones complicadas aquí en realidad no son necesarias, puede agregarlas directamente a un IntPtr , desde .NET 4.

En tercer lugar, se cambia p en el ciclo, lo que no es malo por sí solo, pero se hace de una manera que pierde el rastro del puntero original. toReturn.cells = p; y Marshal.FreeHGlobal(p); use una p que no se refiera al área que asignó, usan una p que ahora apunta justo más allá del final de los datos (bueno, apuntaría allí si p se actualizara en la cantidad correcta). Debe recordarse la p original.

En cuarto lugar, liberar los datos antes de devolverlos significa que ahora ya no existen, por lo que cualquier código al que se pasen estos datos todavía no los tiene: tiene un puntero a nada que no será válido para usar (puede funcionar accidentalmente, pero es peligroso e incorrecto).

Los tres primeros puntos son fáciles de arreglar, pero el último necesita un cambio no local en el funcionamiento de su aplicación: la memoria no se puede liberar aquí, pero debería liberarse en algún momento, es decir, cuando el usuario de los datos haya terminado. con eso.

Algunas correcciones aplicadas:

 int stride = columns * sizeof(double); IntPtr p = Marshal.AllocHGlobal(rows * stride); for (int i = 0; i < rows; i++) //rows { double[] temp = new double[columns]; for (int x = 0; x < columns; x++) temp[x] = input.cells[i, x]; Marshal.Copy(temp, 0, p + stride * i, columns); } toReturn.cells = p; return toReturn;

Tenga en cuenta que aún debe liberar la memoria en el momento adecuado.

over 4 years ago · Santiago Trujillo Report

0

¿Qué pasa con el uso de GHandles para llevar el IntPtr a una matriz? Primero hice una copia para evitar que el cliente sobrescribiera los datos. Desafortunadamente, debe mantener un GHandle para llamar a .Free() para evitar pérdidas de memoria. Esto impulsa la decisión de mantener no solo un IntPtr en las salidas, sino también el GHandle y la longitud de bytes FYI.

 static class Program { static void Main(string[] args) { Inputs inputs = new Inputs(); inputs.Cells = new double[,] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; var outputs = Prepare(inputs); Console.WriteLine(outputs.CellPtr); Console.WriteLine("Finish."); } static Outputs Prepare(Inputs inputs) { Outputs outputs = new Outputs(); outputs.ByteSize = Buffer.ByteLength(inputs.Cells); var temp = new double[inputs.Cells.GetLength(0), inputs.Cells.GetLength(1)]; Buffer.BlockCopy(inputs.Cells, 0, temp, 0, outputs.ByteSize); outputs.Handle = GCHandle.Alloc(inputs.Cells, GCHandleType.Pinned); outputs.CellPtr = outputs.Handle.AddrOfPinnedObject(); return outputs; } } public class Inputs { public double[,] Cells { get; set; } } public class Outputs : IDisposable { public IntPtr CellPtr { get; set; } public int ByteSize { get; set; } public GCHandle Handle { get; set; } #region IDisposable Support private bool disposedValue = false; // To detect redundant calls protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { // dispose managed resources here } Handle.Free(); CellPtr = IntPtr.Zero; ByteSize = 0; disposedValue = true; } } ~Outputs() { // Do not change this code. Put cleanup code in Dispose(bool disposing) above. Dispose(false); } // This code added to correctly implement the disposable pattern. public void Dispose() { Dispose(true); } #endregion }
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!